package com.smm.util;



import com.smm.entity.User;


import io.jsonwebtoken.*;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.misc.BASE64Decoder;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * JwtToken class
 * 使用非对称加密算法
 *
 * @author lhq
 */
public class JwtUtils {

    private static final String SECRET = "h8t^$r1%qK8rvmbUm5453VR#H1sMWLTj!#neA39";
    //private static final int EXPIRE_TIME = 5*60*1000;
    private static Logger log = LoggerFactory.getLogger(JwtUtils.class);


    public static final String AUTH_HEADER_KEY = "Authorization";

    public static final String TOKEN_PREFIX = "Bearer ";

    /**
     * 读取资源文件
     *
     * @param fileName 文件的名称密钥文件
     * @return
     */
    public static String readResourceKey(String fileName) {
        String key = null;
        try {
            InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);
            assert inputStream != null;
            key = IOUtils.toString(inputStream, String.valueOf(StandardCharsets.UTF_8));
        } catch (IOException e) {
            log.error("密钥读取异常", e);
            //e.printStackTrace();
        }
        return key;
    }

    /**
     * 构建token
     *
     * @param user      用户对象
     * @param ttlMillis token生存时间
     * @return
     * @throws Exception
     */
    public static String buildJwtRS256(User user, long ttlMillis) {
        try {

            SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.RS256;
            // 读取私钥
            String privateKeyString = readResourceKey("static/rsa_private_key_pkcs8.pem");
           // String publicKeyString = readResourceKey("static/rsa_public_key.pem");

            // 生成签名密钥
            byte[] keyBytes = (new BASE64Decoder()).decodeBuffer(privateKeyString);

            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);

            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PrivateKey privateKey = keyFactory.generatePrivate(keySpec);

            // 生成JWT的时间
            long nowMillis = System.currentTimeMillis();
            Date now = new Date(nowMillis);
            //创建payload的私有声明（根据特定的业务需要添加，如果要拿这个做验证，一般是需要和jwt的接收方提前沟通好验证方式的）
            Map<String, Object> claims = new HashMap<String, Object>();
            claims.put("userid", user.getId());
            claims.put("username", user.getUsername());
            claims.put("role", user.getRole());

            // 生成jwt文件
            JwtBuilder builder = Jwts.builder()
                    // 这里其实就是new一个JwtBuilder，设置jwt的body
                    // 如果有私有声明，一定要先设置这个自己创建的私有的声明，这个是给builder的claim赋值，一旦写在标准的声明赋值之后，就是覆盖了那些标准的声明的
                    .setClaims(claims)
                    .setHeaderParam("typ", "JWT")
                    .setIssuedAt(now)
                    //不要把敏感信息放入token 比如密码
                    //.setSubject(JSON.toJSONString(user))
                    .signWith(signatureAlgorithm, privateKey);

            // 如果配置了过期时间
            if (ttlMillis >= 0) {
                // 当前时间加上过期的秒数
                long expMillis = nowMillis + ttlMillis;
                Date exp = new Date(expMillis);
                // 设置过期时间
                builder.setExpiration(exp);
            }
            return builder.compact();

        } catch (Exception e) {
            //e.printStackTrace();
            log.error("token生成失败", e);
            return null;
        }

    }

    /**
     * 解密Jwt内容
     *
     * @param token
     * @return
     */
    public static Claims parseJwtRS256(String token) throws ExpiredJwtException, IOException, NoSuchAlgorithmException, InvalidKeySpecException {
        Claims claims = null;
        String cut  = token.substring(7);
        log.info("切割后："+cut);
        // 读取公钥
        String key = readResourceKey("static/rsa_public_key.pem");
        // 生成签名公钥
        byte[] keyBytes = (new BASE64Decoder()).decodeBuffer(key);

        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");

        PublicKey publicKey = keyFactory.generatePublic(keySpec);
        log.info(token);
        claims = Jwts.parser().setSigningKey(publicKey).parseClaimsJws(cut).getBody();

        return claims;
    }

}

